/** ****************************************************************************
* @file 	modbus.h
* @author 	mojinpan
* @copyright (c) 2022-20xx, mojinpan All rights reserved.
* @brief 	modbus协议组件
* 
* @version 	V1.0 
* @date 	2024-2-14
* @details
* 1.定义程序框架
*******************************************************************************/
#ifndef __MODBUS_H_
#define __MODBUS_H_

#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>

/*
PDU : 基础通信层无关的简单协议数据单元
ADU : 应用数据单元
ADU = PDU + 帧头帧尾
*/

/*------------------------------------------------------------------------------
Macro Definition 宏定义
------------------------------------------------------------------------------*/
#define MODBUS_MASTER_FUNC_DEF_NUM    8             //默认功能码数量  
#define MODBUS_MASTER_FUNC_EXT_NUM    0             //可扩展功能码数量

#define MODBUS_SLAVE_FUNC_DEF_NUM     8             //默认功能码数量  
#define MODBUS_SLAVE_FUNC_EXT_NUM     0             //可扩展功能码数量 

#define MODBUS_PDU_MAX              253             // 最大PDU报文长度
#define MODBUS_RTU_ADU_MAX          256             // RTU中最大ADU报文长度
#define MODBUS_TCP_ADU_MAX          260             // TCP中最大ADU报文长度

/*------------------------------------------------------------------------------
Type declaration 类型声明
------------------------------------------------------------------------------*/
//协议类型
typedef enum modbus_protocol_type
{
	MODBUS_PDU,	// PDU模式
    MODBUS_RTU,	// RTU模式
	MODBUS_TCP, // TCP模式
} MbusMode_t;
//寄存器类型
typedef enum ModbusDataType
{
	MODBUS_REG_0x,      // 线圈(MODBUS_COIL)
	MODBUS_REG_1x,   	// 离散输入(MODBUS_DISCRETE_INPUT)
	MODBUS_REG_4x,		// 保持寄存器(MODBUS_HOLDING_REGISTER)
	MODBUS_REG_3x,  	// 输入寄存器(MODBUS_INPUT_REGISTER)
} ModbusDataType_t;
//错误类型
typedef enum Modbusinfo
{
	MODBUS_RECV_WAIT                =  2,	// 接收中
    MODBUS_SNED_OK                  =  1,	// 已发送
    MODBUS_OK                       =  0,	// 没有错误
	MODBUS_EXCEP_ILLEGAL_FUNCTION   = -1,   // 功能码错误
	MODBUS_EXCEP_ILLEGAL_ADDRESS    = -2,   // 数据地址错误
	MODBUS_EXCEP_ILLEGAL_VALUE      = -3,   // 数据值错误
	MODBUS_EXCEP_SLAVE_FAILURE      = -4,   // 从机无法处理该请求
	MODBUS_EXCEP_ACK                = -5,   // 已响应
	MODBUS_EXCEP_NACK               = -7,   // 未响应
	MODBUS_ERR_LEN                  = -11,	// 帧长度错误
	MODBUS_ERR_ALLOC                = -12,	// 内存分配错误
	MODBUS_ERR_FUNC                 = -13,	// 功能码错误
	MODBUS_ERR_COUNT                = -14,	// 寄存器数量错误
	MODBUS_ERR_INDEX                = -15,	// 索引值错误
	MODBUS_ERR_VALUE                = -16,	// 寄存器值错误
	MODBUS_ERR_RANGE                = -17,	// 寄存器错误
	MODBUS_ERR_CRC                  = -18,	// CRC错误
	MODBUS_ERR_PROTOCOL             = -19,	// TCP协议标识符错误
	MODBUS_ERR_TRANSACTION          = -20,	// TCP传输标识符错误
	MODBUS_ERR_ADDR                 = -21,	// 从机地址错误
	MODBUS_ERR_OTHER                = -22,	// 其他错误
    MODBUS_ERR_SEND                 = -23,	// 发送错误
    MODBUS_ERR_RECV                 = -24,	// 接收错误
} ModbusInfo_t;

struct ModbusBuffer;
//modbus缓冲区定义
typedef struct ModbusBuffer
{
    int (*allocator)(struct ModbusBuffer *buffer,uint16_t size,void *cxt);// 内存分配函数指针
	uint8_t *data;              // ADU报文指针
	uint16_t len;               // ADU报文长度
	uint8_t *pdu;               // DPU报文指针
	uint16_t plen;              // ADU报文长度
	uint8_t padding;            // ADU中添加到PDU的额外字节数
	uint8_t pduOffset;          // PDU在ADU中帧的偏移
    uint8_t addr;               // 从机地址
    uint8_t unitId;             // 单元标识符
    uint16_t txId;              // 传输事务标识符
    uint8_t func;               // 功能码
} ModbusBuffer;

// 将Modbus函数ID与指向响应解析函数的指针相关联
typedef int(*modusFunc_t)(void *obj,uint8_t func,uint16_t idx,void *reg,uint16_t cnt);
typedef struct ModbusFunc
{
	uint8_t id;
	modusFunc_t request;
	modusFunc_t response;
} ModbusFunc_t;

//接口对象
typedef struct modubs_prot
{
	int(*recv)(void* cxt,uint8_t* buf,size_t len);	//接收数据
	int(*send)(void* cxt,uint8_t* buf,size_t len);	//发送数据
} Modbus_Port_t;
// 主机模式设备状态
typedef struct ModbusMaster
{
    MbusMode_t mode;                                                                    // modbus模式
    bool isSent;                                                                        // 报文已发送
    uint16_t addr;                                                                      // 从机地址
    uint16_t txId;                                                                      // 事务标识符
    uint8_t unitId;                                                                     // 单元标识符
	ModbusFunc_t funcList[MODBUS_MASTER_FUNC_DEF_NUM + MODBUS_MASTER_FUNC_EXT_NUM]; 	// 报文处理函数
	uint8_t funcNum; 								                                    // 支持的功能码数量													
	ModbusBuffer send;								                                    // 存储master对slave的请求
    ModbusBuffer recv;                                                                  // 存储slave对master的响应
    Modbus_Port_t port;                                                                 // 接口对象
	void *cxt; 										                                    // 用户级上下文信息
}ModbusMaster_t;

// 从机设备状态
typedef struct ModbusSlave
{
    MbusMode_t mode;                                                                    // modbus模式
    uint16_t addr;                                                                      // 从机地址
    int (*readCallback )(void* cxt,uint8_t type,uint16_t addr,uint16_t* val);           // 寄存器读回调
    int (*writeCallback)(void* cxt,uint8_t type,uint16_t addr,uint16_t  val);           // 寄存器写回调         
	ModbusFunc_t funcList[MODBUS_SLAVE_FUNC_DEF_NUM + MODBUS_SLAVE_FUNC_EXT_NUM]; 	    // 报文处理函数
	uint8_t funcNum; 								                                    // 支持的功能码数量		
	ModbusBuffer send;								                                    // 存储slave对master的响应
    ModbusBuffer recv;                                                                  // 存储master对slave的请求
    Modbus_Port_t port;                                                                 // 接口对象
	void *cxt; 									                                        // 用户上下文信息
}ModbusSlave_t;

/*------------------------------------------------------------------------------
Inline function 内联函数
------------------------------------------------------------------------------*/

/** ****************************************************************************
 * @brief  按小端模式读取数据
 * @param p 大端数据指针
 * @return 小端模式的数据
 *******************************************************************************/
static inline uint16_t modbusRLE(const uint8_t *p)
{
    uint8_t lo = *p;
    uint8_t hi = *(p + 1);
    return (uint16_t)lo | ((uint16_t)hi << 8);
}
/** ****************************************************************************
 * @brief  按小端模式写数据数据
 * @param p 小端数据指针
 * @param val 待写入的大端数据
 * @return 写入的大端数据
 *******************************************************************************/
static inline uint16_t modbusWLE(uint8_t *p, uint16_t val)
{
    *p = val & 0xff;
    *(p + 1) = val >> 8;
    return val;
}
/** ****************************************************************************
 * @brief  按大端模式读取数据
 * @param p 小端数据指针
 * @return 大端模式的数据
 *******************************************************************************/
static inline uint16_t modbusRBE(const uint8_t *p)
{
    uint8_t lo = *(p + 1);
    uint8_t hi = *p;
    return (uint16_t)lo | ((uint16_t)hi << 8);
}
/** ****************************************************************************
 * @brief  按大端模式写数据数据
 * @param p 大端数据指针
 * @param val 待写入的小端数据
 * @return 写入的小端数据
 *******************************************************************************/
static inline uint16_t modbusWBE(uint8_t *p, uint16_t val)
{
    *p = val >> 8;
    *(p + 1) = val & 0xff;
    return val;
}
/** ****************************************************************************
 * @brief  按位向阵列中写入数据
 * @param mask 阵列指针
 * @param n bit位置
 * @param value bit值
 *******************************************************************************/
static inline void modbusMaskWrite(uint8_t *mask, uint16_t n, uint8_t value)
{
    if (value)
        mask[n >> 3] |= (1 << (n & 7));
    else
        mask[n >> 3] &= ~(1 << (n & 7));
}
/** ****************************************************************************
 * @brief  按位从阵列中读取数据
 * @param mask 阵列指针
 * @param n bit位置
 * @return bit值
 *******************************************************************************/
static inline uint8_t modbusMaskRead(const uint8_t *mask, uint16_t n)
{
    return (mask[n >> 3] & (1 << (n & 7))) != 0;
}

/*------------------------------------------------------------------------------
Function declaration 函数声明
------------------------------------------------------------------------------*/
ModbusInfo_t Modbus_MasterInit(ModbusMaster_t *obj,MbusMode_t mode,uint8_t addrOrId);
ModbusInfo_t Modbus_MasterFuncSet(ModbusMaster_t *obj,uint8_t id, modusFunc_t request,modusFunc_t response);

ModbusInfo_t Modbus_MasterFunc(ModbusMaster_t *obj, uint8_t func, uint16_t idx, uint16_t cnt,uint16_t* reg);
ModbusInfo_t Modbus_MasterRead(ModbusMaster_t *obj, ModbusDataType_t type, uint16_t addr, uint16_t cnt,uint16_t* buf);
ModbusInfo_t Modbus_MasterWrite(ModbusMaster_t *obj, ModbusDataType_t type, uint16_t addr, uint16_t cnt,uint16_t* buf);

ModbusInfo_t Modbus_SlaveInit(ModbusSlave_t *obj,MbusMode_t mode,uint8_t addr);
ModbusInfo_t Modbus_SlaveFuncSet(ModbusSlave_t *obj,uint8_t id,modusFunc_t response);
int Modbus_SlaveGetFrameLen(MbusMode_t mode,uint8_t* frame);
ModbusInfo_t Modbus_SlaveTask(ModbusSlave_t *obj);

#endif	

/*********************************END OF FILE**********************************/
